/* eslint-disable */
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const ThemeColorReplacer = require('webpack-theme-color-replacer');
const forElementUI = require('webpack-theme-color-replacer/forElementUI');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { chain, set, each } = require('lodash');
const {
  externals,
  cdnLink,
} = require('./dependencies-cdn')();

// 拼接路径
const resolve = dir => require('path').join(__dirname, dir)

// 增加环境变量
process.env.VUE_APP_VERSION = require('./package.json').version
process.env.VUE_APP_BUILD_TIME = require('dayjs')().format('YYYY-MM-DD HH:mm:ss')

// 基础路径 注意发布之前要先修改这里
const publicPath = process.env.VUE_APP_PUBLIC_PATH || '/'
// You can change the port by the following method:
// port = 9527 npm run dev OR npm run dev --port = 9527
const port = process.env.VUE_APP_PORT || 9527; // dev port
const name = process.env.VUE_APP_TITLE || 'vue Element3 Admin'; // page title

// 多页配置，默认未开启，如需要请参考 https://cli.vuejs.org/zh/config/#pages
const pages = undefined

// console.log('vue.config.js', process.env);

// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
  /**
   * You will need to set publicPath if you plan to deploy your site under a sub path,
   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
   * then publicPath should be set to "/bar/".
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   * // 指定子路径。比如，如果你的应用部署在
   * // https://www.xxx.com/my-app/
   * // 那么将这个值改为 `/my-app/`
   */
  publicPath,

  // 将构建好的文件输出到哪里
  outputDir: 'dist',

  /**
   * 放置静态资源的地方 (js/css/img/font/...)
   * build时会把css和js收进assetsDir中
   */
  assetsDir: 'static',

  /**
   * 是否在保存的时候使用 `eslint-loader` 进行检查。
   * 有效的值：`true` | `false` | `"error"`
   * 当设置为 `"error"` 时，检查出的错误会触发编译失败。
   */
  lintOnSave: process.env.NODE_ENV === 'development',

  /**
   * 使用带有浏览器内编译器的完整构建版本
   * 查阅 https://cn.vuejs.org/v2/guide/installation.html#运行时-编译器-vs-只包含运行时
   */
  // compiler: false, // 过时写法
  runtimeCompiler: false,

  /**
   * babel-loader 默认会跳过 node_modules 依赖。
   * 通过这个选项可以显式转译一个依赖。
   * transpileDependencies: [` string or regex `],
   */

  // 是否为生产环境构建生成 source map?
  productionSourceMap: false,

  /**
   * 在生产环境下为 Babel 和 TypeScript 使用 `thread-loader`
   * 在多核机器下会默认开启。
   */
  parallel: require('os').cpus().length > 1,

  /**
   * PWA 插件的选项。
   * 查阅 https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-cli-plugin-pwa/README.md
   */
  pwa: {},

  // CSS 相关选项
  css: {
    // 将组件内的 CSS 提取到一个单独的 CSS 文件 (只用在生产环境中)
    // 也可以是一个传递给 `extract-text-webpack-plugin` 的选项对象
    extract: true,

    // 是否开启 CSS source map？
    sourceMap: false,

    // 为预处理器的 loader 传递自定义选项。比如传递给
    // sass-loader 时，使用 `{ sass: { ... } }`。
    loaderOptions: {},

    // 为所有的 CSS 及其预处理文件开启 CSS Modules。
    // 这个选项不会影响 `*.vue` 文件。
    // 启用 CSS modules for all css / pre-processor files.
    // modules: false, // 过时写法
    requireModuleExtension: true,
  },

  pages,

  // 配置 webpack-dev-server 行为。
  devServer: {
    // [node 查询操作系统 process.platform process.arch](https://vimsky.com/examples/usage/node-js-process-platform-property.html)
    open: false,
    host: '0.0.0.0',
    port,
    overlay: {
      warnings: false,
      errors: true,
    },
    hot: true,
    compress: true,
    progress: true,
    https: false,
    // hotOnly: false,
    // 查阅 https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-cli/cli-service.md#配置代理
    proxy: null, // string | Object
    // before: app => {},
    // 关闭 host check，方便使用 ngrok 之类的内网转发工具
    disableHostCheck: process.env.NODE_ENV === 'development',
  },

  // 调整内部的 webpack 配置。
  // 查阅 https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-cli/webpack.md
  configureWebpack: (/* config */) => {
    // NOTICE: 此处是函数则返回一个新对象;此处是对象则列出需要修改的key-value即可; 默认去merge config
    const newConfig = {};
    /**
     * 在webpack的name字段中提供应用程序的标题。
     * 可以在index.html中对其进行访问以注入正确的标题。
     * htmlWebpackPlugin.options.title => webpackConfig.name
     */
    newConfig.name = name;
    /**
     * cli自带的别名设置
     * alias: {
     *   '@': 'D:\\Project\\vue-ele3-admin\\src',
     *   'vue$': 'vue/dist/vue.runtime.esm-bundler.js'
     * },
     */
    if (process.env.NODE_ENV === 'production') {
      newConfig.externals = externals;
      newConfig.plugins = [
        // gzip
        // 报错`Cannot read property 'tapPromise' of undefined`: 降至@5.0.1
        new CompressionWebpackPlugin({
          filename: '[path].gz[query]',
          test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),
          threshold: 10240,
          minRatio: 0.8,
          deleteOriginalAssets: false
        })
      ]
    }
    return newConfig;
  },

  // 默认设置: https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-service/lib/config/base.js
  chainWebpack(config) {
    /**
     * 添加 CDN 参数到 htmlWebpackPlugin 配置中
     * NOTICE: [在html中遍历htmlWebpackPlugin.options.cdn]
     * 已适配多页
     */
    const htmlPluginNames = chain(pages).keys().map(page => 'html-' + page).value()
    const targetHtmlPluginNames = htmlPluginNames.length ? htmlPluginNames : ['html']
    each(targetHtmlPluginNames, name => {
      config.plugin(name).tap(options => {
        set(options, '[0].cdn', process.env.NODE_ENV === 'production' ? cdnLink : [])
        return options
      })
    })

    // [预加载] it can improve the speed of the first screen, it is recommended to turn on preload
    // config.plugin('preload').tap(() => [
    //   {
    //     rel: 'preload',
    //     // [to ignore runtime.js](https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171)
    //     fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
    //     include: 'initial',
    //   },
    // ]);

    /**
     * 删除懒加载模块的 prefetch preload，降低带宽压力
     * https://cli.vuejs.org/zh/guide/html-and-static-assets.html#prefetch
     * https://cli.vuejs.org/zh/guide/html-and-static-assets.html#preload
     * 而且预渲染时生成的 prefetch 标签是 modern 版本的，低版本浏览器是不需要的
     */
    config.plugins
      .delete('prefetch')
      .delete('preload');

     // 解决 cli3 热更新失效 https://github.com/vuejs/vue-cli/issues/1559
    // config.resolve
    //   .symlinks(true);

    config
      .plugin('theme-color-replacer')
      .use(ThemeColorReplacer, [{
        fileName: 'css/theme-colors.[contenthash:8].css',
        matchColors: [
          // Element-ui主色系列: https://www.jianshu.com/p/10a9fe676145
          // NOTICE:process.env.VUE_APP_ELEMENT_COLOR必须是Element的主色#409EFF
          ...forElementUI.getElementUISeries(process.env.VUE_APP_ELEMENT_COLOR)
        ],
        externalCssFiles: ['./node_modules/element-plus/lib/theme-chalk/index.css'], // optional, String or string array. Set external css files (such as cdn css) to extract colors.
        changeSelector: forElementUI.changeSelector,
      }]);

    config
      // 开发环境 sourcemap 不包含列信息
      .when(process.env.NODE_ENV === 'development',
        config => config.devtool('cheap-source-map')
      )
      // 预览环境构建 vue-loader 添加 filename
      // .when(
      //   process.env.VUE_APP_SCOURCE_LINK === 'TRUE',
      //   config => VueFilenameInjector(config, {
      //     propName: process.env.VUE_APP_SOURCE_VIEWER_PROP_NAME
      //   })
      // );

    // markdown
    config.module
      .rule('md')
      .test(/\.md$/)
      .use('text-loader')
      .loader('text-loader')
      .end()

    // set svg-sprite-loader
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end();
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        // [name],即原始svg的id值
        symbolId: 'icon-[name]',
      })
      .end();

    /**
     * image exclude
     * NOTICE: 当规则`rule('images')`排除掉svg之后，不再聚合精灵图到body中
     */
    // config.module.rule('images')
    //   .test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/)
    //   .exclude
    //   .add(resolve('src/assets/svg-icons/icons'))
    //   .end()

    // 重新设置 alias
    config.resolve.alias
      .set('@api', resolve('src/api'))

    // 分析工具
    if (process.env.npm_config_report) {
      config
        .plugin('webpack-bundle-analyzer')
        .use(BundleAnalyzerPlugin)
    }

    config
      .when(
        process.env.NODE_ENV !== 'development',
        // config => {
        () => {
          config
            .plugin('ScriptExtHtmlWebpackPlugin')
            .after('html')
            .use('script-ext-html-webpack-plugin', [{
              // `runtime` must same as runtimeChunk name. default is `runtime`
              inline: /runtime\..*\.js$/,
            }])
            .end();
          config
            .optimization.splitChunks({
              chunks: 'all',
              cacheGroups: {
                libs: {
                  name: 'chunk-libs',
                  test: /[\\/]node_modules[\\/]/,
                  priority: 10,
                  chunks: 'initial', // only package third parties that are initially dependent
                },
                elementUI: {
                  name: 'chunk-elementUI', // split elementUI into a single package
                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?element-plus(.*)/, // in order to adapt to cnpm
                },
                commons: {
                  name: 'chunk-commons',
                  test: resolve('src/components'), // can customize your rules
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true,
                },
              },
            });
          // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
          config.optimization.runtimeChunk('single');
        },
      );
  },

  // 三方插件的选项
  pluginOptions: {
    // ...
  },
};
